# Copyright (c) 2009 Stefan van der Haven
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import time
import datetime
import urllib
import hmac
import hashlib
import base64
import random

def _get_posix_time():
    return str(int(time.mktime(datetime.datetime.now().timetuple())))

def hmac_sha1(key, text):
    return hmac.new(key, text, hashlib.sha1).digest()

class OAuthSigner(object):
    
    OAUTH_VERSION = '1.0'
    OAUTH_SIGNATURE_METHOD = 'HMAC-SHA1'
    
    def __init__(self, consumer_key, consumer_secret):
        self.consumer_key, self.consumer_secret = consumer_key, consumer_secret

    def _create_nonce(self):
        return str(random.randint(0, 0xffffffff))
    
    def _calculate_signature(self, uri, request_method, request_data, token_secret):
        request_data = dict(request_data)
        # oauth_signature and realm are not included in the signature
        # calculation, so we get rid of them
        request_data.pop('oauth_signature', None)
        request_data.pop('realm', None)
        
        normalized_request_data = u'&'.join(
            u'%s=%s' % (key, urllib.quote(unicode(value), '')) for key, value in
            sorted(request_data.items())
        )
        signature_base_items =  [
            request_method, uri, normalized_request_data
        ]
        signature_base = u'&'.join(
            [urllib.quote(item, u'') for item in signature_base_items] 
        )

        signature_key = u'%s&%s' % (
            urllib.quote(self.consumer_secret, ''),
            urllib.quote(token_secret, '')
        )
        return base64.b64encode(hmac_sha1(signature_key, signature_base))

    def sign_request_data(self, uri, request_method, request_data, token='',
        token_secret=''
    ):
        request_data = dict(request_data)
        request_data.update({
            'oauth_consumer_key': self.consumer_key,
            'oauth_token': token,
            'oauth_signature_method': self.OAUTH_SIGNATURE_METHOD,
            'oauth_version': self.OAUTH_VERSION,
            'oauth_timestamp': _get_posix_time(),
            'oauth_nonce': self._create_nonce(),   
        })
        request_data['oauth_signature'] = self._calculate_signature(
            uri, request_method, request_data, token_secret
        )
        
        return request_data